package com.gmrz.webauthn.protocol.v1.schema;

import com.gmrz.uaf.crypto.CryptoConstants;
import com.gmrz.util.Convert;
import com.gmrz.webauthn.common.WebAuthnRuntimeException;
import com.gmrz.webauthn.protocol.v1.processor.WebAuthnErrorCode;
import com.google.common.primitives.Bytes;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

import java.math.BigInteger;


public class JsonWebKey {
    private transient String rawPublicKey;
    @SerializedName("alg")
    @Expose
    private SignAlgorithmIdentifier alg;
    @SerializedName("x")
    @Expose
    private BigInteger x;
    @SerializedName("y")
    @Expose
    private BigInteger y;
    @SerializedName("n")
    @Expose
    private BigInteger n;
    @SerializedName("e")
    @Expose
    private BigInteger e;

    public SignAlgorithmIdentifier getAlg() {
        return this.alg;
    }

    public BigInteger getX() {
        return this.x;
    }

    public BigInteger getY() {
        return this.y;
    }

    public BigInteger getE() {
        return this.e;
    }

    public BigInteger getN() {
        return this.n;
    }

    public void setAlg(SignAlgorithmIdentifier alg) {
        this.alg = alg;
    }

    public void setX(BigInteger x) {
        this.x = x;
    }

    public void setY(BigInteger y) {
        this.y = y;
    }

    public void setE(BigInteger e) {
        this.e = e;
    }

    public void setN(BigInteger n) {
        this.n = n;
    }

    public String getPublicKeyInRawFormat() {
        if (this.rawPublicKey == null) {
            byte[] raw_key = null;

            switch (this.alg) {

                case ES256:
                case ES384:
                case ES512:
                    raw_key = new byte[65];
                    raw_key[0] = 4;
                    System.arraycopy(this.x.toByteArray(), 0, raw_key, 1, 32);
                    System.arraycopy(this.y.toByteArray(), 0, raw_key, 33, 32);
                    break;


                case RS1:
                case RS256:
                case RS384:
                case RS512:
                case PS256:
                case PS384:
                case PS512:
                    raw_key = Bytes.concat(new byte[][]{this.n.toByteArray(), this.e.toByteArray()});
                    break;

                default:
                    throw new WebAuthnRuntimeException(WebAuthnErrorCode.ERROR_KEY_FORMAT_NOT_FOUND, "The public key format is not supported");
            }


            this.rawPublicKey = Convert.toBase64(raw_key);
        }

        return this.rawPublicKey;
    }

    public int getPublicKeyFormat() {
        switch (this.alg) {
            case ES256:
            case ES384:
            case ES512:
                return CryptoConstants.UAFAlgkey.UAF_ALG_KEY_ECC_X962_RAW.getFormat();

            case RS1:
            case RS256:
            case RS384:
            case RS512:
            case PS256:
            case PS384:
            case PS512:
                return CryptoConstants.UAFAlgkey.UAF_ALG_KEY_RSA_2048_PSS_RAW.getFormat();
        }

        throw new WebAuthnRuntimeException(WebAuthnErrorCode.ERROR_KEY_FORMAT_NOT_FOUND, "The key format is not supported");
    }


    public void setRawPublicKey(String rawPublicKey) {
        this.rawPublicKey = rawPublicKey;
    }
}
